import { Button } from 'antd';
import React, { useState, useContext, useEffect, useReducer } from 'react'
/**
 * useContext基础使用
 */
// 声明 TS 类型
type ContextType = {
    count: number;
    setCount: React.Dispatch<React.SetStateAction<number>>;
    getCount: (val: number) => void
}

// 1. 创建 Context 对象
const AppContext = React.createContext<ContextType>({} as ContextType)
// 定义独立的 Wrapper 组件，被 Wrapper 嵌套的子组件会被 Provider 注入数据
export const Wrapper: React.FC<React.PropsWithChildren> = (props) => {
    // 1. 定义要共享的数据
    const [count, setCount] = useState(0)
    const getCount = (val: number) => {
        setTimeout(() => {
            setCount(val);
        }, 800);
    }
    useEffect(() => {
        getCount(10)
    }, [])
    // 2. 使用 AppContext.Provider 向下共享数据
    return <AppContext.Provider value={{ count, setCount, getCount }}>{props.children}</AppContext.Provider>
}
const LevelA: React.FC = () => {
    const ctx = useContext(AppContext)
    return (
        <>

            <div style={{ padding: 30, backgroundColor: 'lightblue', width: '50vw' }}>
                <p>count值是：{ctx.count}</p>
                <button onClick={() => ctx.setCount((prev) => prev + 1)}>+1</button>
                {/* 2. 使用 Context.Provider 向下传递数据 */}

                <LevelB />
            </div>

        </>

    )
}

const LevelB: React.FC = () => {
    return (
        <div style={{ padding: 30, backgroundColor: 'lightgreen' }}>
            <LevelC />
        </div>
    )
}

const LevelC: React.FC = () => {
    // 3. 使用 useContext 接收数据
    const ctx = useContext(AppContext)

    return (
        <div style={{ padding: 30, backgroundColor: 'lightsalmon' }}>
            {/* 4. 使用 ctx 中的数据和方法 */}
            <p>count值是：{ctx.count}</p>
            <Button onClick={() => ctx.setCount((prev) => prev + 1)}>+1</Button>
            <Button onClick={() => ctx.setCount(0)}>重置</Button>
            <Button onClick={() => ctx.getCount(20)}>异步获取</Button>
        </div>
    )
}
/**
 * useContext 重构 useReducer 案例
 */
// 定义状态的数据类型
type UserType = typeof defaultState
// 1. 定义 action 的类型
type ActionType = { type: 'UPDATE_NAME'; payload: string } | { type: 'INCREMENT'; payload: number } | { type: 'RESET' }
// 1. 定义 Context 的 TS 类型
// 在这一步，我们必须先明确要向子组件注入的数据都有哪些
type UserInfoContextType = { user: UserType; dispatch: React.Dispatch<ActionType> }
// 2. 创建 Context 对象
const UserInfoContext = React.createContext({} as UserInfoContextType)
const defaultState = { name: 'liulongbin', age: 16.56 }
const initAction = (initState: UserType) => {
    console.log('触发了 initAction 函数,只会在函数初始化的时候调用');
    // 把 return 的对象，作为 useReducer 的初始值
    return { ...initState, age: Math.round(Math.abs(initState.age)) || 18 }
}
// 给 initState 指定类型为 UserType
const reducer = (prevState: UserType, action: ActionType) => {
    // 打印 action 的值，终端显示的值为：
    console.log('触发了 reducer 函数', action)
    // 3. 删掉之前的代码，再重复编写这段逻辑的时候，会出现 TS 的类型提示，非常 Nice
    switch (action.type) {
        case 'RESET':
            return initAction(defaultState)
        case 'INCREMENT':
            return { ...prevState, age: prevState.age + action.payload }
        case 'UPDATE_NAME':
            return { ...prevState, name: action.payload }
        default:
            return prevState
    }
}
// 3. 创建 ContextWrapper 组件
export const UserInfoContextWrapper: React.FC<React.PropsWithChildren> = ({ children }) => {
    const [state, dispatch] = useReducer(reducer, defaultState, initAction)
    return <UserInfoContext.Provider value={{ user: state, dispatch }}>
        {children}
    </UserInfoContext.Provider>
}
export const Father: React.FC = () => {
    // 4. 调用 useContext 导入需要的数据
    const { user: state, dispatch } = useContext(UserInfoContext)

    const changeUserName = () => dispatch({ type: 'UPDATE_NAME', payload: '刘龙彬' })

    return (
        <div>
            <button onClick={changeUserName}>修改用户名</button>
            <p>{JSON.stringify(state)}</p>
            <div className="father">
                {/* 5. 这里没有必要再往子组件传递 props 了 */}
                {/* <Son1 {...state} dispatch={dispatch} />
          <Son2 {...state} dispatch={dispatch} /> */}
                <Son1 />
                <Son2 />
            </div>
        </div>
    )
}
const Son1: React.FC = () => {
    const { dispatch, user } = useContext(UserInfoContext)
    const add = () => {
        dispatch({
            type: "INCREMENT",
            payload: 1
        })
    }
    return <>
        <p>Son1用户信息：</p>
        <p>{JSON.stringify(user)}</p>
        <Button onClick={add} type="primary">+1</Button>
    </>
}
const Son2: React.FC = () => {
    const { dispatch, user } = useContext(UserInfoContext)
    const reduce = () => {
        dispatch({
            type: "INCREMENT",
            payload: -2
        })
    }
    return <><p>Son2用户信息：</p>
        <p>{JSON.stringify(user)}</p>
        <Button onClick={reduce} type="primary">-2</Button>
        <GrandSon ></GrandSon>
    </>
}
const GrandSon: React.FC = () => {
    const { dispatch } = useContext(UserInfoContext)
    const reset = () => {
        dispatch({ type: 'RESET' })
    }
    return <>
        <h2>GrandSon</h2>
        <Button onClick={reset}>重置数据</Button>
    </>
}
export default () => (
    <>
        <h1>useContext</h1>
        <Wrapper>
            <LevelA></LevelA>
        </Wrapper>
        <h1>useContext&&useReducer</h1>
        <UserInfoContextWrapper>
            <Father />
        </UserInfoContextWrapper>
    </>


) 